const players = [
  { name: '科比', num: 24 },
  { name: '詹姆斯', num: 23 },
  { name: '保罗', num: 3 },
  { name: '威少', num: 0 },
  { name: '杜兰特', num: 35 },
];

{
  // forEach
  Array.prototype._forEach = function (callback) {
    for (let i = 0; i < this.length; i++) {
      callback(this[i], i, this);
    }
  };

  // forEach正常是不能跳出循环的，如何跳出？？？
  // 利用抛出异常
  let arr = [...new Array(10).keys()];
  try {
    arr.forEach((item) => {
      console.log(`item:${item}`);
      if (item > 5) {
        throw new Error('break');
      }
    });
  } catch (error) {
    if (error.message === 'break') {
      console.log('break success!');
    } else {
      console.error(error);
    }
  }
}

{
  // map
  Array.prototype._map = function (callback) {
    // 检查入参
    if (
      !Array.isArray(this) ||
      !this.length ||
      typeof callback !== 'function'
    ) {
      return [];
    }
    const res = []; // 每次调用map都会返回新数组
    // 遍历数组，讲每次结果放入cb执行，然后push到新数组，返回
    for (let i = 0; i < this.length; i++) {
      res.push(callback(this[i], i, this));
    }
    return res;
  };
}

{
  // 用reduce实现map
  Array.prototype.myMap = function (cb) {
    if (typeof cb !== 'function') {
      throw new Error(`${fn} is not a function`);
    }

    return this.reduce((prev, curr, idx, arr) => {
      return prev.concat(cb(curr, idx, arr));
    }, []);
  };

  let arr = [2, 3, 1, 5];
  arr.myMap(function (item, index, arr) {
    console.log(item, index, arr);
  });
  let res = arr.myMap((v) => v * 2);
  console.log(res); // [4, 6, 2, 10]
}

{
  // filter
  Array.prototype._filter = function (callback) {
    // 检查入参
    if (
      !Array.isArray(this) ||
      !this.length ||
      typeof callback !== 'function'
    ) {
      return [];
    }

    const res = [];
    for (let i = 0; i < this.length; i++) {
      // 符合预期的结果放入新数组
      // 注意这里与map不一样
      if (callback(this[i], i, this)) {
        res.push(callback(this[i], i, this));
      }
    }
    return res;
  };
}

{
  // every
  Array.prototype._every = function (callback) {
    for (let i = 0; i < this.length; i++) {
      if (!callback(this[i], i, this)) {
        return false;
      }
    }
    return true;
  };
}

{
  // some
  Array.prototype._some = function (callback) {
    for (let i = 0; i < this.length; i++) {
      if (callback(this[i], i, this)) {
        return true;
      }
    }
    return false;
  };
}

{
  // 手写简单reduce
  // 参数 ：一个回掉函数，一个初始化参数（非必须）
  // 回掉函数有四个参数（res: 代表累加值，cur: 目前值，index: 第几个，arr: 调用reduce的数组）
  // 整体返回res累加值

  Array.prototype._reduce = function (callback, initValue) {
    // this 就是调用reduce的数组
    let arr = this;

    if (!Array.isArray(arr)) {
      throw new TypeError('Reduce of empty array with no initial value');
    }

    // 判断有没有初始值，没有就取第一个值
    // let res = arguments.length > 1 ? initValue : arr.splice(0, 1)[0]
    let res = arguments.length > 1 ? initValue : arr.shift();

    arr.forEach((item, index) => {
      // callback 每次执行完毕都会返回一个新的res，覆盖之前的res
      res = callback(res, item, index, arr);
    });

    return res;
  };

  let arr = [1, 2, 3, 4];
  let result = arr._reduce((res, cur) => {
    return res + cur;
  });
  console.log(result);
}

{
  // reduce
  Array.prototype._reduce = function (callback, initValue) {
    let start = 0,
      res;

    if (initValue) {
      res = initValue;
    } else {
      start = 1;
      res = this[0];
    }

    for (let i = start; i < this.length; i++) {
      res = callback(res, this[i], i, this);
    }

    return res;
  };
}

{
  // find
  Array.prototype._find = function (fn) {
    let result = undefined;
    for (let i = 0; i < this.length; i++) {
      if (fn(this[i], i, this)) {
        result = this[i];
        break;
      }
    }
    return result;
  };
}

{
  // findIndex
  Array.prototype._findIndex = function (callback) {
    for (let i = 0; i < this.length; i++) {
      if (callback(this[i], i, this)) {
        return i;
      }
    }
    return -1;
  };
}

{
  // fill
  Array.prototype._fill = function (value, start, end) {
    start = start || 0;
    end = end || this.length;
    for (let i = start; i < end; i++) {
      this[i] = value;
    }
    return this;
  };
}

{
  // includes
  Array.prototype._includes = function (value, start = 0) {
    if (start < 0) {
      start = this + start;
    }
    const isNaN = Number.isNaN(value);
    for (let i = start; i < this.length; i++) {
      if (this[i] === value || (isNaN && Number.isNaN(this[i]) === isNaN)) {
        return true;
      }
    }
    return false;
  };
  console.log([1, 2, 3]._includes(2)); // true
  console.log([1, 2, 3, NaN]._includes(NaN)); // true
  console.log([1, 2, 3]._includes(1, 1)); // false
}

{
  // join
  Array.prototype._join = function (s = ',') {
    let str = '';
    for (let i = 0; i < this.length; i++) {
      if (i === this.length - 1) {
        str += `${this[i]}`;
      } else {
        str += `${this[i]}${s}`;
      }
    }
    return str;
  };
  console.log([1, 2, 3]._join()); // 1,2,3
  console.log([1, 2, 3]._join('*')); // 1*2*3
}

{
  // flat
  Array.prototype._flat = function () {
    let arr = this;
    while (arr.some((item) => Array.isArray(item))) {
      arr = [].concat(...arr);
    }
    return arr;
  };

  const testArr = [1, [2, 3, [4, 5]], [8, 9]];

  console.log(testArr._flat());
}

{
  // reverse
  Array.prototype._reverse = function () {
    let arr = this;
    for (let i = 0; i < arr.length / 2; i++) {
      // 第一个和最后一个交换位置
      // 第二个和倒数第二个交换位置
      // ...
      // 以此类推
      // 长度为n的数组需要交换n/2 + 1次
      [arr[i], arr[arr.length - 1 - i]] = [arr[arr.length - 1 - i], arr[i]];
    }
    return arr;
    // 倒着遍历
    // const result = [];
    // for (let i = arr.length - 1; i >= 0; i--) {
    //   result.push(arr[i]);
    // }
    // return result;
  };

  console.log([1, 2, 3, 4, 5]._reverse());
}
